﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using System.Net;
using System.Web;
using System.Text.RegularExpressions;
using System.Threading;
using System.Runtime.InteropServices;
using System.Collections;
using _12306Bot.AuthCode;
using _12306Bot.Common;
using System.Data;
using System.Text;
using Microsoft.Win32;

namespace _12306Bot
{
    public partial class FrmMain : Form
    {
        //发送消息的共通类
        private WebBot wbLink;

        //Cookie的容器
        private CookieContainer cookconReq = new CookieContainer();

        private Dictionary<String, String> dicStation;
        //车次信息
        TrainInfo ti;

        /// <summary>
        /// 初始化时间间隔
        /// </summary>
        private const Int32 i32InitInterval = 1000;

        //页面Cookie设置
        [DllImport("wininet.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern bool InternetSetCookie(string lpszUrlName, string lbszCookieName, string lpszCookieData);

        /// <summary>
        /// 微博秀的地址
        /// </summary>
        private String strWeiBoUrl;
        /// <summary>
        /// 状态机状态备份
        /// </summary>
        private int PgmAccessBackup = 0;
        /// <summary>
        /// 订票数量限制
        /// </summary>
        private int iOrderLimit;
        /// <summary>
        /// 由等待状态转为订票状态的时间延迟
        /// <para>整点开始刷票似乎还不行，要延迟一段时间</para>
        /// </summary>
        private const int iOrderDelay = 25000;
        /// <summary>
        /// 错误代码
        /// <para>因无尽模式而特别将此变量转为全局，方便判断</para>
        /// </summary>
        private String strErrCode = "";

        /// <summary>
        /// 程序身份标识
        /// </summary>
        private String strIdentify = "ThisIs12306BOT";

        /// <summary>
        /// CDN
        /// </summary>
        private CDN c = new CDN();

        public FrmMain()
        {
            InitializeComponent();
        }

        private void btnReLoginAndSearch_Click(object sender, EventArgs e)
        {
            //页面输入Check
            if (!checkInput())
            {
                return;
            }

            //按钮设置
            btnPause.Visible = true;
            btnReLoginAndSearch.Visible = false;

            try
            {
                if (bgdWorkerReLoginAndSearch.IsBusy)
                {
                    txtLog.AppendText("♢程序已经在运行了，请稍后再点击开始。\r\n");
                    return;
                }
                this.bgdWorkerReLoginAndSearch.RunWorkerAsync();
            }
            catch (Exception ex)
            {
                MessageBox.Show(wbLink.strProcessError(ex), "出错了，请重试", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        /// <summary>
        /// 输入检查
        /// </summary>
        /// <returns>是否输入正确</returns>
        private Boolean checkInput()
        {
            String strErrMsg = "";
            if (txtUserName.Text == "")
            {
                strErrMsg += "用户名未输入\r\n";
            }

            if (txtPassword.Text == "")
            {
                strErrMsg += "密码未输入\r\n";
            }

            //if (txtLoginPassCode.Text == "")
            //{
            //    strErrMsg += "登录的验证码未输入\r\n";
            //}

            //if (txtLoginIntev.Text == "")
            //{
            //    strErrMsg += "登录间隔时间未输入\r\n";
            //}

            //Regex rgNum = new Regex(@"^[0-9]*$");
            //if (!rgNum.IsMatch(txtLoginIntev.Text))
            //{
            //    strErrMsg += "登录间隔时间应该为整数\r\n";
            //}

            if (txtFromStation.Text == "")
            {
                strErrMsg += "发站未输入\r\n";
            }

            if (txtToStation.Text == "")
            {
                strErrMsg += "到站未输入\r\n";
            }

            if (txtTrainCode.Text == "")
            {
                strErrMsg += "车次未输入，如想订多趟车，请多开\r\n";
            }

            Regex rgTrainCoide = new Regex(@"^[A-Za-z0-9]+$");
            if (!rgTrainCoide.IsMatch(txtTrainCode.Text))
            {
                strErrMsg += "车次只能输入字母和数字，请以12306车票预订界面公布的车次为准\r\n";
            }

            //if (txtMinIntev.Text == "")
            //{
            //    strErrMsg += "间隔时间未输入\r\n";
            //}
            //if (txtMaxIntev.Text == "")
            //{
            //    strErrMsg += "间隔时间未输入\r\n";
            //}
            //Regex rgNum = new Regex(@"^[0-9]*$");
            //if (!rgNum.IsMatch(txtIntev.Text))
            //{
            //    strErrMsg += "间隔时间应该为整数\r\n";
            //}

            if (lbSeatType.SelectedItem == null)
            {
                strErrMsg += "席别未选择\r\n";
            }

            //if (txtOrderPassCode.Text == "")
            //{
            //    strErrMsg += "订票的验证码未输入\r\n";
            //}

            //乘车人信息
            if (dgvInfo.Rows.Count <= 1)
            {
                strErrMsg += "乘车人信息未输入\r\n";
            }

            if (dgvInfo.Rows.Count - 1 > iOrderLimit)
            {
                strErrMsg += "你最多还能订" + iOrderLimit + "张票\r\n";
            }

            Boolean IsdgvRowHasEmptyCell;
            for (int i = 0; i < dgvInfo.Rows.Count - 1; i++)
            {
                IsdgvRowHasEmptyCell = false;
                for (int j = 0; j < dgvInfo.Columns.Count; j++)
                {
                    IsdgvRowHasEmptyCell |= (dgvInfo.Rows[i].Cells[j].Value == null || dgvInfo.Rows[i].Cells[j].Value.ToString() == "");
                }
                if (IsdgvRowHasEmptyCell)
                {
                    strErrMsg += "请完整填写乘车人信息的第" + (i+1) + "行，或单击选中该行并按Delete键删除\r\n";
                }
            }

            if (strErrMsg != "")
            {
                MessageBox.Show(strErrMsg, "出错了，请重试", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return false;
            }
            return true;
        }

        private void bgdWorkerReLoginAndSearch_DoWork(object sender, DoWorkEventArgs e)
        {
            DoReLoginAndSearch();
        }

        /// <summary>
        /// 一括处理登录及检索
        /// </summary>
        private void DoReLoginAndSearch()
        {
            //设置线程为后台线程，以便在主线程退出时退出
            Thread.CurrentThread.IsBackground = true;

            //最外层是无尽模式的循环
            do
            {

                //登陆次数
                int iLoginCount = 1;
                //查询次数
                int iSearchCount = 1;
                //订票次数
                int iOrderCount = 1;
                //车次错误查询计数器
                int iGetTrainInfoErrCount = 0;

                //登陆时的动态Js链接
                String strLoginDynamicJS = "";
                //Login随机值
                String strLoginRand = "";
                //Login随机隐藏控件
                String strLoginRandControl = "";
                //订票前动态Js链接
                String strQueryDynamicJS = "";
                //订票前随机隐藏控件
                String strQueryRandControl = "";
                //订票时动态Js链接
                String strOrderDynamicJS = "";
                //订票时随机隐藏控件
                String strOrderRandControl = "";
                //车站列表的链接
                String strStationUrl = "";

                //余票信息
                String strLeftTicket = "";
                //Token
                String strToken = "";

                //状态机状态
                //0:初始态;10:获取loginRand;20:获取验证码并识别;30:登陆;35:获取车站列表的链接;40:获取车站列表;45:等待放票;50:查询车次;
                //60:进入订票页面;70:获取验证码并识别;73:订票信息验证;80:订票;90:处理订票状态;900:放音乐
                //-999:停机
                int iPgmStatus = PgmAccessBackup;

                try
                {
                    do
                    {
                        //备份状态机状态，使得暂停可以恢复
                        //PgmAccessBackup == -1 表示完全停止
                        if (PgmAccessBackup != -1)
                        {
                            PgmAccessBackup = iPgmStatus;
                        }
                        else
                        {
                            //置0为后面处理方便
                            PgmAccessBackup = 0;
                        }

                        //手动停止
                        if (bgdWorkerReLoginAndSearch.CancellationPending)
                        {
                            txtLog.AppendText("♢手动停止成功。\r\n");
                            //PgmAccessBackup > 900意味着所有操作都做完了，可以重新来了
                            if (PgmAccessBackup > 900) PgmAccessBackup = 0;
                            resetForm(PgmAccessBackup);
                            return;
                        }

                        
                        if (iPgmStatus != 0)
                        {
                            //休息一下
                            //一开始不用休息
                            //没填时间间隔则默认休息5000秒
                            if (txtMinIntev.Text == "" || Convert.ToInt32(txtMinIntev.Text) < 4)
                            {
                                txtMinIntev.Text = "4";
                            }
                            if (txtMaxIntev.Text == "" || Convert.ToInt32(txtMaxIntev.Text) < 8)
                            {
                                txtMaxIntev.Text = "8";
                            }
                            int i = (new Random()).Next(Convert.ToInt32(txtMinIntev.Text), Convert.ToInt32(txtMaxIntev.Text));
                            Thread.Sleep(i * 1000);
                        } else {
                            //初始态
                            //重置Cookie
                            cookconReq = new CookieContainer();
                            //成功就继续，失败就再获取
                            switch (InitPage(ref strLoginDynamicJS))
                            {
                                case 0:
                                    txtLog.AppendText("♢初始化页面信息失败。将重新尝试。\r\n");
                                    iPgmStatus = 0;
                                    break;
                                case 1:
                                    txtLog.AppendText("♢初始化页面信息第一步成功。\r\n");
                                    iPgmStatus = 5;
                                    break;
                            }
                            //强制开始下一次循环，以暂停程序
                            continue;
                        }

                        if (iPgmStatus == 5)
                        {
                            strLoginRandControl = getRandControl(strLoginDynamicJS);
                            if (strLoginRandControl != "")
                            {
                                txtLog.AppendText("♢初始化页面信息第二步成功。\r\n");
                                iPgmStatus = 10;
                            }
                            else
                            {
                                txtLog.AppendText("♢初始化页面信息失败。将重新尝试。\r\n");
                                iPgmStatus = 0;
                            }
                        }

                        //获取loginRand
                        if (iPgmStatus == 10)
                        {
                            //成功就继续，失败就再获取
                            switch (LoginPrepare(ref strLoginRand))
                            {
                                case 0:
                                    txtLog.AppendText("♢初始化登陆信息失败。将重新尝试。\r\n");
                                    iPgmStatus = 10;
                                    break;
                                case 1:
                                    txtLog.AppendText("♢初始化登陆信息成功。\r\n");
                                    iPgmStatus = 20;
                                    break;
                            }
                            //强制开始下一次循环，以暂停程序
                            continue;
                        }

                        //获取验证码并识别
                        if (iPgmStatus == 20)
                        {
                            //成功就继续，失败就再获取
                            txtLog.AppendText("♢开始获取验证码。\r\n");
                            switch (getPassCode((new Random(DateTime.Now.Millisecond).NextDouble()).ToString(), 'L'))
                            {
                                case 0:
                                    txtLog.AppendText("♢验证码获取失败。\r\n");
                                    iPgmStatus = 20;
                                    break;
                                //验证码获取成功
                                case 1:
                                    txtLog.AppendText("♢验证码获取成功。\r\n");
                                    iPgmStatus = 25;
                                    break;
                            }
                        }

                        //识别验证码
                        if (iPgmStatus == 25)
                        {
                            //成功就继续，失败就再获取
                            txtLog.AppendText("♢开始识别验证码。\r\n");
                            if (identifyAuthCode('L'))
                            {
                                //成功
                                iPgmStatus = 30;
                            }
                            else
                            {
                                //失败
                                iPgmStatus = 20;
                            }
                        }

                        //登陆
                        if (iPgmStatus == 30)
                        {
                            txtLog.AppendText("♢信心满满地执行第" + iLoginCount++ + "次登录。\r\n");
                            switch (Login(strLoginRand, strLoginRandControl))
                            {
                                //登陆失败
                                case 0:
                                    //暂时认为这里不需要显示错误Log，因为ErrLog已经做了。
                                    //出错重新初始化
                                    txtLog.AppendText("♢登录失败，请自行根据上一条信息判断是否需要手动停止，程序默认重新开始登录。\r\n");
                                    iPgmStatus = 0;
                                    break;
                                //登陆成功
                                case 1:
                                    txtLog.AppendText("♢登录成功啦。\r\n");
                                    //手动识别验证码的话保存图片
                                    //SaveAuthCode('L');
                                    iPgmStatus = 35;
                                    break;
                                //验证码错误
                                case -10:
                                    iPgmStatus = 10;
                                    break;
                                //停机级错误
                                case -999:
                                    iPgmStatus = -999;
                                    break;
                            }
                            //强制开始下一次循环，以暂停程序
                            continue;
                        }

                        //获取车站列表的链接
                        if (iPgmStatus == 35)
                        {
                            txtLog.AppendText("♢初始化车站相关信息。\r\n");
                            switch (getStationJsUrl(ref strStationUrl, ref strQueryDynamicJS))
                            {
                                //没有获取到链接，重新刷
                                case 0:
                                    txtLog.AppendText("♢初始化失败，再来一遍。\r\n");
                                    iPgmStatus = 35;
                                    break;
                                //成功
                                case 1:
                                    iPgmStatus = 37;
                                    break;
                                //被踢
                                case -900:
                                    iPgmStatus = 0;
                                    txtLog.AppendText("♢服务器说他不认识你了。没办法，我们再登录一次吧。\r\n");
                                    break;
                            }
                            //直接前进到下一步，不休息
                        }

                        if (iPgmStatus == 37)
                        {
                            strQueryRandControl = getRandControl(strQueryDynamicJS);
                            if (strLoginRandControl != "")
                            {
                                txtLog.AppendText("♢查询准备成功。\r\n");
                                iPgmStatus = 40;
                            }
                            else
                            {
                                txtLog.AppendText("♢查询准备失败。将重新尝试。\r\n");
                                iPgmStatus = 35;
                            }
                        }

                        //获取车站列表
                        if (iPgmStatus == 40)
                        {
                            dicStation = new Dictionary<string, string>();
                            switch (getStationDic(ref dicStation, strStationUrl))
                            {
                                //获取失败
                                case 0:
                                    txtLog.AppendText("♢车站列表获取失败，将重新尝试。\r\n");
                                    iPgmStatus = 40;
                                    break;
                                //获取成功
                                case 1:
                                    txtLog.AppendText("♢车站列表获取成功。\r\n");
                                    iPgmStatus = 45;
                                    break;
                                //停机级错误
                                case -999:
                                    iPgmStatus = -999;
                                    break;
                            }
                            //强制开始下一次循环，以暂停程序
                            continue;
                        }

                        //等待放票
                        if (iPgmStatus == 45)
                        {
                            if (dtpStartTime.Value.Hour == 0)
                            {
                                iPgmStatus = 50;
                            }
                            else
                            {
                                txtLog.AppendText("♢保持连接，等待放票。\r\n♢如需立刻开始订票，请将起售时间的小时设为0。\r\n");
                                switch (maintainConnection())
                                {
                                    //时间未到，停留在本方法
                                    case 0:
                                        txtLog.AppendText("♢当前服务器时间为：" + wbLink.DteServer.ToLongTimeString() + "\r\n");
                                        iPgmStatus = 45;
                                        break;
                                    //时间超过，前进至下一方法
                                    case 1:
                                        txtLog.AppendText("♢时间到咯，开始抢票！\r\n");
                                        iPgmStatus = 50;
                                        break;
                                    //被踢
                                    case -900:
                                        iPgmStatus = 0;
                                        txtLog.AppendText("♢服务器说他不认识你了。没办法，我们再登录一次吧。\r\n");
                                        break;
                                    //停机级错误
                                    case -999:
                                        iPgmStatus = -999;
                                        break;
                                }
                                //强制开始下一次循环，以暂停程序
                                continue;
                            }
                        }

                        //查询车次
                        if (iPgmStatus == 50)
                        {
                            txtLog.AppendText("♢有条不紊地进行第" + iSearchCount++ + "次查询。\r\n");
                            txtLog.AppendText("♢请注意，任何时候都不要放弃电话订票！\r\n");
                            switch (getTrainInfo())
                            {
                                //成功
                                case 1:
                                    iPgmStatus = 60;

                                    txtLog.AppendText("♢" + ti.Station_train_code + "次列车有部分余票\r\n");
                                    //重设页面的起止站
                                    txtFromStation.Text = ti.From_station_name;
                                    txtToStation.Text = ti.To_station_name;

                                    iGetTrainInfoErrCount = 0;
                                    break;
                                //没有车票
                                case 10:
                                    iPgmStatus = 50;
                                    //未获取到车票，则ti对象为空
                                    //txtLog.AppendText(ti.Station_train_code + "次列车没有余票了，刷到它出票为止。");
                                    txtLog.AppendText("♢" + txtTrainCode.Text + "次列车没有余票了，刷到它出票为止。\r\n");
                                    iGetTrainInfoErrCount = 0;
                                    break;
                                //连接失败
                                case -1:
                                    iPgmStatus = 50;
                                    txtLog.AppendText("♢服务器说他很忙，不高兴理你。我们不管，继续骚扰他。\r\n");
                                    break;
                                //找不到车次
                                case -20:
                                    iGetTrainInfoErrCount++;
                                    if (iGetTrainInfoErrCount >= 10)
                                    {
                                        txtLog.AppendText("♢我找了" + iGetTrainInfoErrCount + "次都没找到车。肯定是你的错，不是我的错。我不干了！\r\n");
                                        //停机
                                        iPgmStatus = -999;
                                    }
                                    else
                                    {
                                        txtLog.AppendText("♢内个……你填的车次好像找不到，我再找找看吧。如果是你填错了，麻烦手动停止。\r\n");
                                        iPgmStatus = 50;
                                    }
                                    break;
                                case -30:
                                    txtLog.AppendText("【错误】发站名不正确，请核实并填写完整。\r\n");
                                    //停机
                                    iPgmStatus = -999;
                                    break;
                                case -40:
                                    txtLog.AppendText("【错误】到站名不正确，请核实并填写完整。\r\n");
                                    //停机
                                    iPgmStatus = -999;
                                    break;
                                //被踢
                                case -900:
                                    iPgmStatus = 0;
                                    txtLog.AppendText("♢服务器说他不认识你了。没办法，我们再登录一次吧。\r\n");
                                    break;
                            }
                            //强制开始下一次循环，以暂停程序
                            continue;
                        }

                        
                        //票务信息描述
                        String strLeftTicketDescription;
                        //进入订票页面
                        if (iPgmStatus == 60)
                        {
                            txtLog.AppendText("♢胜利就在眼前！开始第" + iOrderCount++ + "次订票。\r\n");
                            txtLog.AppendText("♢请注意，任何时候都不要放弃电话订票！\r\n");
                            switch (LoadOrderPage(ref strToken, ref strLeftTicket, out strLeftTicketDescription, strQueryRandControl, ref strOrderDynamicJS))
                            {
                                case 1:
                                    txtLog.AppendText("♢准备预订：" + lbSeatType.Text + "\r\n");
                                    txtLog.AppendText("♢票务信息：" + strLeftTicketDescription + "\r\n");
                                    txtLog.AppendText("♢此票务信息不一定靠谱。o(╯□╰)o\r\n");
                                    iPgmStatus = 65;
                                    break;
                                case -10:
                                    txtLog.AppendText("♢⊙﹏⊙ 几个亿的垃圾系统又出问题了。准备重试。\r\n");
                                    iPgmStatus = 60;
                                    break;
                                //席别找不到
                                case -20:
                                    txtLog.AppendText("♢你选的那个席别好像压根儿就没有唉！重新输入吧。\r\n");
                                    iPgmStatus = -999;
                                    break;
                                //系统要求重新查询余票
                                case -40:
                                    txtLog.AppendText("♢系统要求重新查询余票。\r\n");
                                    iPgmStatus = 50;
                                    break;
                                //手动输入验证码时，余票少于需订票
                                case -50:
                                    txtLog.AppendText("♢余票不足，继续刷票。\r\n");
                                    iPgmStatus = 50;
                                    break;
                                //移到后面去
                                //case -30:
                                //    txtLog.AppendText("♢票务信息：" + strLeftTicketDescription + "\r\n");
                                //    txtLog.AppendText("♢此票务信息不一定靠谱。o(╯□╰)o\r\n");
                                //    txtLog.AppendText("♢没有座位，重新刷新。\r\n");
                                //    iPgmStatus = 60;
                                //    break;
                                //被踢
                                case -900:
                                    iPgmStatus = 0;
                                    txtLog.AppendText("♢服务器说他不认识你了。没办法，我们再登录一次吧。\r\n");
                                    break;
                                case -999:
                                    iPgmStatus = -999;
                                    break;
                            }
                            //强制开始下一次循环，以暂停程序
                            continue;
                        }

                        if (iPgmStatus == 65)
                        {
                            strOrderRandControl = getRandControl(strOrderDynamicJS);
                            if (strLoginRandControl != "")
                            {
                                txtLog.AppendText("♢订票准备成功。\r\n");
                                iPgmStatus = 70;
                            }
                            else
                            {
                                txtLog.AppendText("♢订票准备失败。将重新尝试。\r\n");
                                iPgmStatus = 60;
                            }
                        }

                        //获取验证码并识别
                        if (iPgmStatus == 70)
                        {
                            //成功就继续，失败就再获取
                            txtLog.AppendText("♢开始获取验证码。\r\n");
                            switch (getPassCode((new Random(DateTime.Now.Millisecond).NextDouble()).ToString(), 'O'))
                            {
                                case 0:
                                    txtLog.AppendText("♢验证码获取失败。\r\n");
                                    iPgmStatus = 70;
                                    break;
                                //验证码获取成功
                                case 1:
                                    txtLog.AppendText("♢验证码获取成功。\r\n");
                                    iPgmStatus = 71;
                                    break;
                            }
                            //直接前进到下一步，不休息
                        }

                        //识别验证码
                        if (iPgmStatus == 71)
                        {
                            //成功就继续，失败就再获取
                            txtLog.AppendText("♢开始识别验证码。\r\n");
                            if (identifyAuthCode('O'))
                            {
                                //成功
                                iPgmStatus = 73;
                                saveAuthCode = true;
                            }
                            else
                            {
                                //失败
                                iPgmStatus = 70;
                            }
                        }

                        //订票信息验证
                        if (iPgmStatus == 73)
                        {
                            switch (checkOrderInfo(strToken, strLeftTicket, strOrderRandControl))
                            {
                                //不知道什么情况下会失败，暂定刷新订票页面吧
                                case 0:
                                    iPgmStatus = 60;
                                    break;
                                case 1:
                                    //手动识别验证码的话保存图片
                                    if (saveAuthCode) SaveAuthCode('O');
                                    saveAuthCode = false;

                                    iPgmStatus = 77;
                                    break;
                            }
                            //成功的话直接前进到下一步，不休息
                        }

                        //订票信息再验证并查询余票
                        if (iPgmStatus == 77)
                        {
                            switch (getTicketInfo(ref strLeftTicket))
                            {
                                //不知道什么情况下会失败，暂定刷新订票页面吧
                                case 0:
                                    iPgmStatus = 60;
                                    break;
                                case 1:
                                    iPgmStatus = 80;
                                    break;
                                case 2:
                                    txtLog.AppendText("♢排队人数大于余票张数，服务器拒绝接受订单。\r\n");
                                    //20130628服务器更新，需要重新获取验证码了
                                    iPgmStatus = 70;
                                    break;
                                case -30:
                                    txtLog.AppendText("♢没有座位，重新刷新。\r\n");
                                    //20130628服务器更新，需要重新获取验证码了
                                    iPgmStatus = 70;
                                    break;
                            }
                            //强制开始下一次循环，以暂停程序
                            continue;
                        }

                        //订票
                        if (iPgmStatus == 80)
                        {
                            txtLog.AppendText("♢提交订单。\r\n");
                            switch (Order(strToken, strLeftTicket, strOrderRandControl))
                            {
                                //成功
                                case 1:
                                    iPgmStatus = 90;
                                    break;
                                //验证码错误
                                case -10:
                                    iPgmStatus = 70;
                                    break;
                                //错误，刷新订票页面
                                case -20:
                                    txtLog.AppendText("♢订票失败，请根据上一条错误信息决定是否要手动停止。程序默认继续刷票。\r\n");
                                    iPgmStatus = 60;
                                    break;
                                case -999:
                                    iPgmStatus = -999;
                                    break;
                            }
                            //强制开始下一次循环，以暂停程序
                            continue;
                        }

                        //处理订票状态
                        if (iPgmStatus == 90)
                        {
                            switch (handleOrderStatus())
                            {
                                //成功
                                case 1:
                                    txtLog.AppendText("★★★★飞天拉面大神保佑，你已成功订票★★★★\r\n");
                                    txtLog.AppendText("当前时间：" + wbLink.DteServer.ToLongTimeString() + "\r\n");
                                    //修改限定数量
                                    iOrderLimit = iOrderLimit - dgvInfo.Rows.Count + 1;
                                    OrderLimit.wbOrderLimitLink = wbLink;
                                    OrderLimit.SetCheck(dgvInfo.Rows.Count - 1);
                                    PopIE();
                                    this.TopMost = true;
                                    this.TopMost = false;
                                    iPgmStatus = 900;
                                    break;
                                //订单状态确认倒计数，刷新自己
                                case -10:
                                    iPgmStatus = 90;
                                    break;
                                //未知错误，刷新订票页面
                                case -20:
                                    txtLog.AppendText("♢再接再励，继续刷。\r\n");
                                    iPgmStatus = 60;
                                    break;
                                case -999:
                                    iPgmStatus = -999;
                                    break;
                            }
                            //强制开始下一次循环，以暂停程序
                            continue;
                        }

                        //放音乐
                        if (iPgmStatus == 900)
                        {
                            playBeep();
                        }

                        //停机
                        if (iPgmStatus == -999)
                        {
                            resetForm(0);
                            //无尽模式
                            //被踢掉就再循环，否则就停止
                            if (strErrCode == "E05")
                            {
                                txtLog.AppendText("■■■无尽模式开启中，重头开始循环■■■\r\n");
                                break;
                            }
                            else
                            {
                                txtLog.AppendText("♢程序已中止，如有需要请重新点击开始！\r\n");
                                return;
                            }
                        }
                    } while (true);
                }
                catch (Exception ex)
                {
                    resetForm(0);
                    txtLog.AppendText("♢意外错误，以下是原因。无尽模式下将自动重新开始。\r\n");
                    txtLog.AppendText(ex.Message + "\r\n");
                    //txtLog.AppendText(ex.StackTrace + "\r\n");
                }

            } while (cbCircle.Checked);
        }

        /// <summary>
        /// 初始化页面
        /// </summary>
        /// <returns>0:失败;1:成功</returns>
        private int InitPage(ref String strLoginDynamicJS)
        {
            //返回数据的流
            HttpWebResponse respRtn;

            Uri uriInit = new Uri(wbLink.uriBase, "otsweb/loginAction.do?method=init");

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uriInit);
            request.Accept = "text/html, application/xhtml+xml, */*";
            request.Referer = wbLink.uriBase + "otsweb/";

            respRtn = wbLink.SendData(request, ref cookconReq);

            //页面返回
            String strPage = "";
            strPage = wbLink.ReadStream(respRtn);

            Regex rgDynamicJsAction = new Regex("(otsweb/dynamicJsAction.do\\?jsversion=(.+?)&method=(.+?))\"");
            strLoginDynamicJS = rgDynamicJsAction.Match(strPage).Groups[1].Value;

            //仅用ErrLog来判断对错
            if (ErrLog.Write(strPage, txtLog) == "C")
            {
                return 1;
            }
            else
            {
                return 0;
            }
        }

        private String getRandControl(String strLoginDynamicJS)
        {
            //返回数据的流
            HttpWebResponse respRtn;

            Uri uriRand = new Uri(wbLink.uriBase, strLoginDynamicJS);

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uriRand);
            request.Accept = "application/javascript, */*;q=0.8";
            request.Referer = wbLink.uriBase + "otsweb/loginAction.do?method=init";

            respRtn = wbLink.SendData(request, ref cookconReq);

            //页面返回
            String strPage = "";
            strPage = wbLink.ReadStream(respRtn);

            //String strJsFunc = strPage.Replace("})(jQuery);", "");
            //strJsFunc = strJsFunc.Replace("(function ($){", "");
            //strJsFunc = strJsFunc.Replace("(function check(src){checkSelf();function checkSelf(){var formArr=$('form');if(formArr.length>1){}}timmer=setInterval(gc,2000);})('1_111');$(document).ready(function(){(function(){var form = document.forms[0];var oldSubmit;if(null!=form && form != 'undefined'){form.oldSubmit = form.submit;form.submit = function (){var keyVlues=gc().split(':');var inputObj=$('<input type=\"hidden\" name=\"'+keyVlues[0]+'\" value=\"'+encode32(bin216(Base32.encrypt(keyVlues[1],keyVlues[0])))+'\" />');var myObj=$('<input type=\"hidden\" name=\"myversion\" value=\"'+window.helperVersion+'\" />');inputObj.appendTo($(form));myObj.appendTo($(form));form.oldSubmit();delete inputObj;delete myObj;}}})();});", "");
            //strJsFunc = strJsFunc.Replace("(function check(src){checkSelf();function checkSelf(){var formArr=$('form');if(formArr.length>1){}}timmer=setInterval(gc,2000);})('1_111');$(document).ready(function(){(function(){var form = $('#orderForm')[0];var oldSubmit;if(null!=form && form != 'undefined'){form.oldSubmit = form.submit;form.submit = function (){var keyVlues=gc().split(':');var inputObj=$('<input type=\"hidden\" name=\"'+keyVlues[0]+'\" value=\"'+encode32(bin216(Base32.encrypt(keyVlues[1],keyVlues[0])))+'\" />');var myObj=$('<input type=\"hidden\" name=\"myversion\" value=\"'+window.helperVersion+'\" />');inputObj.appendTo($(form));myObj.appendTo($(form));form.oldSubmit();delete inputObj;delete myObj;}}})();});", "");
            
            //这样写是因为，本来想用上面那段代码来动态生成的，但是结果很差。对方一变就出问题。
            String strJsFunc = "function bin216(s){var i,l,o = \"\",n;s += \"\";b = \"\";for(i = 0,l = s.length;i < l;i ++ ){b = s.charCodeAt(i);n = b.toString(16);o += n.length < 2 ? \"0\" + n : n;}return o;};var Base32 = new function(){var delta = 0x9E3779B8;function longArrayToString(data,includeLength){var length = data.length;var n = (length - 1) << 2;if (includeLength){var m = data[length - 1];if((m < n - 3) || (m > n))return null;n = m;}for(var i = 0;i < length;i ++ ){data[i] = String.fromCharCode(data[i] & 0xff,data[i] >>> 8 & 0xff,data[i] >>> 16 & 0xff,data[i] >>> 24 & 0xff);}if (includeLength){return data.join('').substring(0, n);}else{return data.join('');}};function stringToLongArray(string, includeLength){var length = string.length;var result = [];for (var i = 0; i < length; i += 4){result[i >> 2] = string.charCodeAt(i) |                string.charCodeAt(i + 1) << 8     |                string.charCodeAt(i + 2) << 16    |                string.charCodeAt(i + 3) << 24;}if (includeLength){result[result.length] = length;}return result;};this.encrypt = function(string, key){if (string == \"\"){return \"\";}var v = stringToLongArray(string, true);var k = stringToLongArray(key, false);if (k.length < 4){k.length = 4;}var n = v.length - 1;var z = v[n], y = v[0];var mx, e, p, q = Math.floor(6 + 52 / (n + 1)), sum = 0;while (0 < q -- ){sum = sum + delta & 0xffffffff;e = sum >>> 2 & 3;for (p = 0; p < n; p ++ ){y = v[p + 1];mx = (z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z);z = v[p] = v[p] + mx & 0xffffffff;}y = v[0];mx = (z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z);z = v[n] = v[n] + mx & 0xffffffff;}return longArrayToString(v, false);};};var keyStr = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\";function encode32(input){input = escape(input);var output = \"\";var chr1, chr2, chr3 = \"\";var enc1, enc2, enc3, enc4 = \"\";var i = 0;do{chr1 = input.charCodeAt(i ++ );chr2 = input.charCodeAt(i ++ );chr3 = input.charCodeAt(i ++ );enc1 = chr1 >> 2;enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);enc4 = chr3 & 63;if (isNaN(chr2)){enc3 = enc4 = 64;}else if (isNaN(chr3)){enc4 = 64;}output = output +             keyStr.charAt(enc1) +             keyStr.charAt(enc2) +             keyStr.charAt(enc3) +             keyStr.charAt(enc4);chr1 = chr2 = chr3 = \"\";enc1 = enc2 = enc3 = enc4 = \"\";}while (i < input.length);return output;};";

            Regex rgDynamicJsKey = new Regex(@"var key='(.+?)';");
            String strDynamicJsKey = rgDynamicJsKey.Match(strPage).Groups[1].Value;
            String strDynamicFunc = "encode32(bin216(Base32.encrypt('1111','" + strDynamicJsKey + "')))";

            return HttpUtility.UrlEncode(strDynamicJsKey) + "=" + HttpUtility.UrlEncode(ExecuteScript(strDynamicFunc, strJsFunc));
            
        }

        /// <summary>
        /// 执行JS
        /// </summary>
        /// <param name="sExpression">参数体</param>
        /// <param name="sCode">JavaScript代码的字符串</param>
        /// <returns></returns>
        private string ExecuteScript(string sExpression, string sCode)
        {
            MSScriptControl.ScriptControl scriptControl = new MSScriptControl.ScriptControl();
            scriptControl.UseSafeSubset = true;
            scriptControl.Language = "JScript";
            scriptControl.AddCode(sCode);
            try
            {
                string str = scriptControl.Eval(sExpression).ToString();
                return str;
            }
            catch (Exception ex)
            {
                string str = ex.Message;
            }
            return null;
        }

        /// <summary>
        /// 登陆准备，获取loginRand
        /// </summary>
        /// <returns>0:失败;1:成功</returns>
        private int LoginPrepare(ref String strLoginRand)
        {
            try
            {
                //返回数据的流
                HttpWebResponse respRtn;

                Uri uriLogin = new Uri(wbLink.uriBase, "otsweb/loginAction.do?method=loginAysnSuggest");

                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uriLogin);
                request.Headers["x-requested-with"] = "XMLHttpRequest";
                request.Referer = wbLink.uriBase + "otsweb/loginAction.do?method=init";
                request.Accept = "application/json, text/javascript, */*";
                request.Headers["Cache-Control"] = "no-cache";

                respRtn = wbLink.SendData(request, ref cookconReq);

                //页面返回
                String strPage = "";
                strPage = wbLink.ReadStream(respRtn);

                Regex rgLoginPrepare = new Regex("{\"loginRand\":\"(.+)?\",\"randError\":");
                strLoginRand = rgLoginPrepare.Match(strPage).Groups[1].Value;
                //仅用ErrLog来判断对错
                if (ErrLog.Write(strPage, txtLog) == "C")
                {
                    return 1;
                }
                else
                {
                    return 0;
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 登陆
        /// </summary>
        /// <returns>0:登陆失败;1:登陆成功;-10:验证码错误;-999:停机级错误</returns>
        private int Login(String strLoginRand, String strLoginRandControl)
        {
            try
            {
                //返回数据的流
                HttpWebResponse respRtn;

                Uri uriLogin = new Uri(wbLink.uriBase, "otsweb/loginAction.do?method=login");
                //String strPostData = "loginRand=" + strLoginRand + "&refundLogin=N&refundFlag=Y&loginUser.user_name=" + HttpUtility.UrlEncode(txtUserName.Text) + "&nameErrorFocus=&user.password=" + HttpUtility.UrlEncode(txtPassword.Text) + "&passwordErrorFocus=&randCode=" + txtLoginPassCode.Text + "&randErrorFocus=";
                String strPostData = "loginRand=" + strLoginRand + "&refundLogin=N&refundFlag=Y&isClick=&form_tk=null&loginUser.user_name=" + HttpUtility.UrlEncode(txtUserName.Text) + "&nameErrorFocus=&user.password=" + HttpUtility.UrlEncode(txtPassword.Text) + "&passwordErrorFocus=&randCode=" + txtLoginPassCode.Text + "&randErrorFocus=&" + strLoginRandControl + "&myversion=undefined";
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uriLogin);
                request.ContentType = "application/x-www-form-urlencoded";
                request.Referer = wbLink.uriBase + "otsweb/loginAction.do?method=init";
                request.Accept = "text/html, application/xhtml+xml, */*";
                request.Headers["Cache-Control"] = "no-cache";

                respRtn = wbLink.SendData(request, strPostData, ref cookconReq);

                //如果有页面重定向的话
                if (respRtn.Headers["Location"] == wbLink.uriBase + "otsweb/order/querySingleAction.do?method=init")
                {
                    return 1;
                }

                //页面返回值
                String strPage;
                strPage = wbLink.ReadStream(respRtn);
                //错误代码
                strErrCode = ErrLog.Write(strPage, txtLog);
                //E打头的错误直接退出
                if (strErrCode.Substring(0, 1) == "E")
                {
                    return -999;
                }
                else
                {
                    //如果验证码错了，重新获取并重新输入验证码
                    if (strErrCode == "W01")
                    {
                        return -10;
                    }
                    //判断是否登录成功
                    if (!IsLogOut(strPage))
                    {
                        //登录成功
                        return 1;
                    }
                     //登录失败
                    return 0;

                    //if (rgIsLogin.Match(  strPage.Contains("/otsweb/loginAction.do?method=logout"))
                    //{
                    //    //登录成功
                    //    return 1;
                    //}
                    //else
                    //{
                    //    //登录失败
                    //    return 0;
                    //}
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 获取站点列表JS的链接地址
        /// </summary>
        /// <returns>0:失败;1:成功;-900:被踢</returns>
        private int getStationJsUrl(ref String strStationUrl, ref String strQueryDynamicJS)
        {
            //返回数据的流
            HttpWebResponse respRtn;
            try
            {
                //获取归属地JS文件的URL
                Uri uriGetJSURL = new Uri(wbLink.uriBase, "/otsweb/order/querySingleAction.do?method=init");
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uriGetJSURL);
                request.Accept = "text/html, application/xhtml+xml, */*";
                request.Referer = wbLink.uriBase + "otsweb/";

                respRtn = wbLink.SendData(request, ref cookconReq);

                Regex rgRTN = new Regex("<script src=\"(/otsweb/js/common/station_name.js\\?version=.*?)\"");
                String strRtn = wbLink.ReadStream(respRtn);

                //被踢
                if (IsLogOut(strRtn))
                {
                    return -900;
                }

                strStationUrl = rgRTN.Match(strRtn).Groups[1].Value;

                Regex rgDynamicJsAction = new Regex("(otsweb/dynamicJsAction.do\\?jsversion=(.+?)&method=(.+?))\"");
                strQueryDynamicJS = rgDynamicJsAction.Match(strRtn).Groups[1].Value;

                if (strStationUrl == "" || strQueryDynamicJS == "")
                {
                    return 0;
                }
                return 1;
            }
            catch (Exception ex)
            {
                throw (ex);
            }
        }

        /// <summary>
        /// 获取车站列表
        /// </summary>
        /// <returns>0:获取失败;1:获取成功;-999:停机级错误</returns>
        private int getStationDic(ref Dictionary<String, String> dicStation, String strStationUrl)
        {
            try
            {
                //返回数据的流
                HttpWebResponse respRtn;

                txtLog.AppendText("♢开始获取车站列表。\r\n");

                //获取归属地JS
                Uri uriGetJS = new Uri(wbLink.uriBase, strStationUrl);
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uriGetJS);
                request.Accept = "application/javascript, */*;q=0.8";

                respRtn = wbLink.SendData(request, ref cookconReq);

                //页面返回值
                String strPage;
                strPage = wbLink.ReadStream(respRtn);

                //返回数据切割
                String[] strsResp = strPage.Replace("';", "").Split('@');

                //从1开始，将“var station_names ='”这一段去掉
                for (int i = 1; i < strsResp.Length; i++)
                {
                    String[] strsStation = strsResp[i].Split('|');
                    dicStation.Add(strsStation[1], strsStation[2]);
                }
                //获取到了站点就返回1，否则返回0
                if (dicStation.Count > 0)
                {
                    return 1;
                }
                else
                {
                    return 0;
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 保持连接，直到起售时刻
        /// </summary>
        /// <returns>0:继续执行本方法;1:前进至下一方法;-900:被踢;-999:停机级错误</returns>
        private int maintainConnection()
        {
            //页面返回值
            String strPage;
            //返回数据的流
            HttpWebResponse respRtn;

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(new Uri(wbLink.uriBase, "otsweb/order/querySingleAction.do?method=init"));
            request.Accept = "text/html, application/xhtml+xml, */*";
            request.Referer = wbLink.uriBase + "otsweb/";

            respRtn = wbLink.SendData(request, ref cookconReq);

            strPage = wbLink.ReadStream(respRtn);
            //被踢
            if (IsLogOut(strPage))
            {
                return -900;
            }

            strErrCode = ErrLog.Write(strPage, txtLog);

            if (strErrCode.Substring(0, 1) == "E")
            {
                //停机级错误
                return -999;
            }
            
            if (wbLink.DteServer.TimeOfDay >= dtpStartTime.Value.TimeOfDay)
            {
                return 1;
            }

            return 0;
        }

        /// <summary>
        /// 检索车次
        /// 错误-1和-10都是写在query_single_bindeve.js的loadData函数里面的
        /// </summary>
        /// <returns>1：表示正常；10：没有车票；-1：服务器忙，连接失败；-20：车次填写错误；-30：发站名不正确；-40：到站名不正确；-900：被踢了</returns>
        private int getTrainInfo()
        {
            try
            {
                //返回数据的流
                HttpWebResponse respRtn;
                //发送的数据
                //String strPostData;
                //返回的数据
                String strRtnData;

                //发站名不正确
                if (!dicStation.ContainsKey(txtFromStation.Text))
                {
                    return -30;
                }
                //到站名不正确
                if (!dicStation.ContainsKey(txtToStation.Text))
                {
                    return -40;
                }

                Uri uriTrainCode = new Uri(wbLink.uriBase, "/otsweb/order/querySingleAction.do?method=queryLeftTicket" +
                                        "&orderRequest.train_date=" + dtpGoDate.Value.ToString("yyyy-MM-dd") +
                                        "&orderRequest.from_station_telecode=" + dicStation[txtFromStation.Text] +
                                        "&orderRequest.to_station_telecode=" + dicStation[txtToStation.Text] +
                                        "&orderRequest.train_no=&trainPassType=QB&trainClass=QB%23D%23Z%23T%23K%23QT%23&includeStudent=00&seatTypeAndNum=" +
                                        "&orderRequest.start_time_str=" + HttpUtility.UrlEncode(cbGoTime.Text));

                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uriTrainCode);
                request.Headers["x-requested-with"] = "XMLHttpRequest";
                request.Referer = wbLink.uriBase + "otsweb/order/querySingleAction.do?method=init";
                request.Accept = "text/plain, */*";
                request.ContentType = "application/x-www-form-urlencoded";
                //request.Headers.Set("Host", "122.228.243.22");
                //wbLink.SetHeaderValue(request.Headers, "Host", "122.228.243.22");

                //wbLink.SetHeaderValue(request.Headers, "Host", c.SdIP. .get [0]);

                respRtn = wbLink.SendData(request, ref cookconReq) ;

                strRtnData = wbLink.ReadStream(respRtn);

                //服务器忙，连接失败
                if (strRtnData == "-1")
                {
                    return -1;
                }
                //被系统踢了
                if (strRtnData == "-10")
                {
                    return -900;
                }

                //查看返回值里面有没有所填的车次
                Regex rgTrainCode = new Regex("onmouseout='(onStopOut\\(\\))'>" + txtTrainCode.Text.ToUpper() + "</span>,.*?<a.*?(onclick=javascript:getSelected\\('(.*?)'\\))?>.*?</a>");
                Match mTrainCode = rgTrainCode.Match(strRtnData);

                if (mTrainCode.Success)
                {
                    //已经获取到车次了
                    if (mTrainCode.Groups[3].Value != "")
                    {
                        ti = new TrainInfo(mTrainCode.Groups[3].Value);
                        return 1;
                    }
                    else
                    {
                        //没有车票
                        return 10;
                    }
                }
                else
                {
                    //没获取到车次
                    return -20;
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }


        /// <summary>
        /// 获取订票页面
        /// </summary>
        /// <param name="strLeftTicket">票务信息</param>
        /// <param name="strToken">Token值</param>
        /// <param name="strLeftTicketDescription">余票描述信息</param>
        /// <param name="strQueryRandControl">订票前随机隐藏控件</param>
        /// <param name="strOrderDynamicJS">订票时动态Js链接</param>
        /// <returns>1:成功;-10:获取页面失败（主要是未找到TOKEN）;-20:席别找不到;-30:不订站票;-40:系统要求重新查询余票;-50:余票不足;-900:被踢;-999:停机级错误</returns>
         private int LoadOrderPage(ref String strToken, ref String strLeftTicket, out String strLeftTicketDescription, String strQueryRandControl, ref String strOrderDynamicJS)
        {
            try
            {
                //返回数据的流
                HttpWebResponse respRtn;
                //发送的数据
                String strPostData;
                //页面返回值
                String strPage;

                strLeftTicketDescription = "";

                Uri uriPreOrder = new Uri(wbLink.uriBase, "otsweb/order/querySingleAction.do?method=submutOrderRequest");

                strPostData =
                    //车次
                    "station_train_code=" + ti.Station_train_code +
                    //发车日期
                    "&train_date=" + dtpGoDate.Value.ToString("yyyy-MM-dd") +
                    "&seattype_num=" +
                    //系统用发站代号
                    "&from_station_telecode=" + ti.From_station_telecode +
                    //系统用到站代号
                    "&to_station_telecode=" + ti.To_station_telecode +
                    "&include_student=00" +
                    //出发站名
                    "&from_station_telecode_name=" + HttpUtility.UrlEncode(ti.From_station_name) +
                    //到达站名
                    "&to_station_telecode_name=" + HttpUtility.UrlEncode(ti.To_station_name) +
                    //日期
                    "&round_train_date=" + DateTime.Now.ToString("yyyy-MM-dd") +
                    "&round_start_time_str=00%3A00--24%3A00&single_round_type=1&train_pass_type=QB&train_class_arr=" + HttpUtility.UrlEncode("QB#D#Z#T#K#QT#") +
                    //查询时所选时间区间
                    "&start_time_str=" + HttpUtility.UrlEncode(cbGoTime.Text) +
                    //历时
                    "&lishi=" + HttpUtility.UrlEncode(ti.Lishi) +
                    //开车时间
                    "&train_start_time=" + HttpUtility.UrlEncode(ti.Train_start_time) +
                    //系统车次编号
                    "&trainno4=" + ti.Trainno4 +
                    //到达时间
                    "&arrive_time=" + HttpUtility.UrlEncode(ti.Arrive_time) +
                    "&from_station_name=" + HttpUtility.UrlEncode(ti.From_station_name) +
                    "&to_station_name=" + HttpUtility.UrlEncode(ti.To_station_name) +
                    "&from_station_no=" + ti.From_station_no +
                    "&to_station_no=" + ti.To_station_no +
                    //订票序列号
                    "&ypInfoDetail=" + ti.YpInfoDetail +
                    "&mmStr=" + ti.MmStr +
                    "&locationCode=" + ti.LocationCode +
                    "&" + strQueryRandControl +
                    "&myversion=undefined";
                
                HttpWebRequest requestOrder = (HttpWebRequest)WebRequest.Create(uriPreOrder);
                requestOrder.Accept = "text/html, application/xhtml+xml, */*";
                requestOrder.Referer = wbLink.uriBase + "otsweb/order/querySingleAction.do?method=init";
                requestOrder.ContentType = "application/x-www-form-urlencoded";
                requestOrder.Headers["Cache-Control"] = "no-cache";

                respRtn = wbLink.SendData(requestOrder, strPostData, ref cookconReq);
                //如果有页面重定向的话
                if (respRtn.Headers["Location"] != null)
                {
                    HttpWebRequest requestConfirm = (HttpWebRequest)WebRequest.Create(respRtn.Headers["Location"]);
                    requestConfirm.Accept = "text/html, application/xhtml+xml, */*";
                    requestConfirm.Referer = wbLink.uriBase + "otsweb/order/querySingleAction.do?method=init";
                    requestConfirm.Headers["Cache-Control"] = "no-cache";

                    respRtn = wbLink.SendData(requestConfirm, ref cookconReq);
                }

                strPage = wbLink.ReadStream(respRtn);
                //被踢
                if (IsLogOut(strPage))
                {
                    return -900;
                }

                strErrCode = ErrLog.Write(strPage, txtLog);

                //E打头的错误直接退出
                if (strErrCode.Substring(0, 1) == "E")
                {
                    return -999;
                }
                else if (strErrCode == "W04")
                {
                    return -40;
                }
                else if (strErrCode.Substring(0, 1) != "C")
                {
                    return -10;
                }

                Regex rgTOKEN = new Regex("org.apache.struts.taglib.html.TOKEN\" value=\"(.+)?\">");
                //没找到TOKEN
                if (!rgTOKEN.Match(strPage).Success)
                {
                    return -10;
                }
                else
                {
                    strToken = rgTOKEN.Match(strPage).Groups[1].Value;
                    //票务信息
                    Regex rgLeftTicket = new Regex("<input type=\"hidden\" name=\"leftTicketStr\" id=\"left_ticket\"\\s*value=\"((?:\\w{10})+?)\" />");

                    strLeftTicket = rgLeftTicket.Match(strPage).Groups[1].Value;

                    //当前选中的席别的票数
                    int iSelectedTicketCount;
                    strLeftTicketDescription = getLeftTicketDescription(strLeftTicket, out iSelectedTicketCount);

                    if (iSelectedTicketCount == -1)
                    {
                        //座席找不到
                        return -20;
                    }

                    if (iSelectedTicketCount < dgvInfo.Rows.Count - 1 && cbLessTicket.Checked)
                    {
                        //余票不足则不订票
                        txtLog.AppendText("♢" + lbSeatType.Text + "还剩" + iSelectedTicketCount + "张票。\r\n");
                        return -50;
                    }

                    Regex rgDynamicJsAction = new Regex("(otsweb/dynamicJsAction.do\\?jsversion=(.+?)&method=(.+?))\"");
                    strOrderDynamicJS = rgDynamicJsAction.Match(strPage).Groups[1].Value;

                    //移到后面去
                    ////选择硬座或者二等座，座位数为0，且不订站票
                    ////则继续刷页面
                    //if ((lbSeatType.SelectedValue.ToString() == "1" || lbSeatType.SelectedValue.ToString() == "O") && iSelectedTicketCount == 0 && cbNoStand.Checked)
                    //{
                    //    return -30;
                    //}
                }

                //成功
                return 1;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 获取余票信息
        /// </summary>
        /// <param name="strLeftTicket">余票信息字符串</param>
        /// <param name="TicketCount">当前选中的席别的票数</param>
        /// <returns>余票信息说明</returns>
        private String getLeftTicketDescription(String strLeftTicket, out int iSelectedTicketCount)
        {
            DataTable dtSeatType = Configuration.getSeatTypeDataTable();
            String strTicketDescription = "";
            //默认-1，表示无此席别
            iSelectedTicketCount = -1;

            foreach (DataRow dr in dtSeatType.Rows)
            {
                Regex rgTicketCount = new Regex(dr[1] + ".{5}(\\d{4})|.{10}");
                MatchCollection mcTicket = rgTicketCount.Matches(strLeftTicket);
                foreach (Match m in mcTicket)
                {
                    //判断(\d{4})有无值，从而判断前半部分有无匹配成功
                    //未匹配成功则进行下一步循环
                    if (m.Groups[1].Value == "")
                    {
                        continue;
                    }
                    int iTicketCount = Convert.ToInt32(m.Groups[1].Value);
                    if (iTicketCount < 3000)
                    {
                        strTicketDescription += dr[0] + "：" + iTicketCount + "张；";
                        //获取当前选中的席别的票数
                        if (dr[1].ToString() == lbSeatType.SelectedValue.ToString())
                        {
                            iSelectedTicketCount = iTicketCount;
                        }
                    }
                    else
                    {
                        strTicketDescription += "站票：" + (iTicketCount - 3000) + "张；";
                    }
                }
            }
            if (strTicketDescription == "")
            {
                strTicketDescription = "未能获取到余票信息。";
            }
            return strTicketDescription;
        }

        /// <summary>
        /// 订票信息验证
        /// <para>20121229修正后必须发送此信息才能够订票成功</para>
        /// </summary>
        /// <returns>0:失败;1:成功;</returns>
        private int checkOrderInfo(String strToken, String strLeftTicket, String strOrderRandControl)
        {
            try
            {
                //发送的数据
                String strPostData = "";
                //页面返回值
                String strPage;

                txtLog.AppendText("♢将订票的怨念注入服务器。\r\n");

                Uri checkOrderInfo = new Uri(wbLink.uriBase, "otsweb/order/confirmPassengerAction.do?method=checkOrderInfo&rand=" + txtOrderPassCode.Text);

                strPostData = combinateConfirmPassengerActionPostData(strToken, strLeftTicket, strOrderRandControl);
                strPostData += "&tFlag = dc";

                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(checkOrderInfo);
                request.Headers["x-requested-with"] = "XMLHttpRequest";
                request.Referer = wbLink.uriBase + "otsweb/order/confirmPassengerAction.do?method=init";
                request.Accept = "application/json, text/javascript, */*";
                request.ContentType = "application/x-www-form-urlencoded";

                HttpWebResponse respRtn = wbLink.SendData(request, strPostData, ref cookconReq);

                strPage = wbLink.ReadStream(respRtn);

                //如果errMsg不等于Y，说明出错了，刷新页面，重新提交
                Regex rgOrder = new Regex("\"errMsg\":\"(.*?)\"");
                if (rgOrder.Match(strPage).Groups[1].Value != "Y")
                {
                    txtLog.AppendText("【错误】" + rgOrder.Match(strPage).Groups[1].Value + "\r\n");
                    return 0;
                }

                return 1;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 订票信息验证
        /// 并返回余票
        /// </summary>
        /// <returns>0:失败;1:成功;2:禁止点击提交;-30:不订站票</returns>
        private int getTicketInfo(ref String strLeftTicket)
        {
            try
            {
                //页面返回值
                String strPage;

                txtLog.AppendText("♢再次获取票务信息。\r\n");

                Uri getTicketInfo = new Uri(wbLink.uriBase, "/otsweb/order/confirmPassengerAction.do?method=getQueueCount&train_date=" + dtpGoDate.Value.ToString("yyyy-MM-dd")
                                                          + "&train_no=" + ti.Trainno4 + "&station=" + ti.Station_train_code + "&seat=" + HttpUtility.UrlEncode(lbSeatType.SelectedValue.ToString())
                                                          + "&from=" + ti.From_station_telecode + "&to=" + ti.To_station_telecode + "&ticket=" + strLeftTicket);

                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(getTicketInfo);
                request.Headers["x-requested-with"] = "XMLHttpRequest";
                request.Referer = wbLink.uriBase + "otsweb/order/confirmPassengerAction.do?method=init";
                request.Accept = "application/json, text/javascript, */*";
                request.ContentType = "application/x-www-form-urlencoded";

                HttpWebResponse respRtn = wbLink.SendData(request, ref cookconReq);

                strPage = wbLink.ReadStream(respRtn);

                Regex rgOrder = new Regex("\"ticket\":\"(.*?)\".*\"op_2\":(.*?)}");
                if (!rgOrder.Match(strPage).Success)
                {
                    txtLog.AppendText("【警告】再次获取票务信息时出错，请将下面的信息发送给作者。\r\n");
                    txtLog.AppendText(strPage + "\r\n");
                    return 0;
                }
                strLeftTicket = rgOrder.Match(strPage).Groups[1].Value;
                //当前选中的席别的票数
                int iSelectedTicketCount;
                String strLeftTicketDescription = getLeftTicketDescription(strLeftTicket, out iSelectedTicketCount);
                txtLog.AppendText("♢票务信息：" + strLeftTicketDescription + "\r\n");
                txtLog.AppendText("♢此票务信息可能靠谱。(￣.￣)+\r\n");

                //选择硬座或者二等座，座位数为0，且不订站票
                //则继续刷页面
                if ((lbSeatType.SelectedValue.ToString() == "1" || lbSeatType.SelectedValue.ToString() == "O") && iSelectedTicketCount == 0 && cbNoStand.Checked)
                {
                    return -30;
                }

                //op_2必须为false才行，否则不能提交
                if (rgOrder.Match(strPage).Groups[2].Value.Trim() == "true")
                {
                    return 2;
                }

                return 1;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        //暂时不处理此方法，因为此方法明显设计不良，只会发送第一个订票人席别给服务器
        ///// <summary>
        ///// 再次获得队列信息
        ///// </summary>
        //private int getQueueCount()
        //{
        //    //Uri getQueueCount = new Uri(wbLink.uriBase, "otsweb/order/confirmPassengerAction.do?method=getQueueCount&train_date=2013-01-01&train_no=5l00000G1811&station=G18&seat=M&from=AOH&to=VNP&ticket=" + strLeftTicket);
        //    Uri getQueueCount = new Uri(wbLink.uriBase, "otsweb/order/confirmPassengerAction.do?method=getQueueCount&train_date=" + dtpGoDate.Value.ToString("yyyy-MM-dd") + "&train_no=" + ti.Trainno4 + "&station=" + ti.Station_train_code + "&seat=M&from=AOH&to=VNP&ticket=" + strLeftTicket);
        //    HttpWebResponse r2 = wbLink.SendData(getQueueCount, ref cookconReq);
        //}

        /// <summary>
        /// 订票
        /// </summary>
        /// <returns>1:订票成功;-10:验证码错误;-20:不明错误;-999:停机级错误</returns>
        private int Order(String strToken, String strLeftTicket, String strOrderRandControl)
        {
            //页面返回值
            String strPage;
            //返回数据的流
            HttpWebResponse respRtn;
            //发送的数据
            String strPostData = "";
            try
            {
                //Uri uriOrder = new Uri(wbLink.uriBase, "otsweb/order/confirmPassengerAction.do?method=confirmSingleForQueueOrder");
                Uri uriOrder = new Uri(wbLink.uriBase, "otsweb/order/confirmPassengerAction.do?method=confirmSingleForQueue");

                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uriOrder);
                request.Headers["x-requested-with"] = "XMLHttpRequest";
                request.Referer = wbLink.uriBase + "otsweb/order/confirmPassengerAction.do?method=init";
                request.Accept = "application/json, text/javascript, */*";
                request.ContentType = "application/x-www-form-urlencoded";

                strPostData = combinateConfirmPassengerActionPostData(strToken, strLeftTicket, strOrderRandControl);

                respRtn = wbLink.SendData(request, strPostData, ref cookconReq);

                //本页面返回一个类似哈希表的东西
                strPage = wbLink.ReadStream(respRtn);

                //查看返回结果
                strErrCode = ErrLog.Write(strPage, txtLog);
                //E打头的错误直接退出
                if (strErrCode.Substring(0, 1) == "E")
                {
                    return -999;
                }
                //验证码出错
                if (strErrCode == "W01")
                {
                    return -10;
                }
                //其他错误
                if (strErrCode.Substring(0, 1) != "C")
                {
                    return -20;
                }
                //如果errMsg不等于Y，说明也出错了，可能是没有票了
                //刷新页面，重新提交
                Regex rgOrder = new Regex("\"errMsg\":\"(.*?)\"");
                if (rgOrder.Match(strPage).Groups[1].Value != "Y")
                {
                    txtLog.AppendText("【警告】" + rgOrder.Match(strPage).Groups[1].Value + "\r\n");
                    return -20;
                }
                //成功
                return 1;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 拼接confirmPassengerAction的Post数据
        /// </summary>
        private String combinateConfirmPassengerActionPostData(String strToken, String strLeftTicket, String strOrderRandControl)
        {
            //发送的数据
            String strPostData = "";

            strPostData = "org.apache.struts.taglib.html.TOKEN=" + strToken;

            strPostData += "&leftTicketStr=" + strLeftTicket;
            strPostData += "&textfield=%E4%B8%AD%E6%96%87%E6%88%96%E6%8B%BC%E9%9F%B3%E9%A6%96%E5%AD%97%E6%AF%8D&checkbox0=0";
            //发车日期
            strPostData += "&orderRequest.train_date=" + dtpGoDate.Value.ToString("yyyy-MM-dd");
            //系统车次编号
            strPostData += "&orderRequest.train_no=" + ti.Trainno4;
            //车次
            strPostData += "&orderRequest.station_train_code=" + ti.Station_train_code;
            //系统用出发站号
            strPostData += "&orderRequest.from_station_telecode=" + ti.From_station_telecode;
            //系统用到达站号
            strPostData += "&orderRequest.to_station_telecode=" + ti.To_station_telecode;
            //不知道
            strPostData += "&orderRequest.seat_type_code=";
            //strPostData += "&orderRequest.seat_detail_type_code=";
            strPostData += "&orderRequest.ticket_type_order_num=";
            strPostData += "&orderRequest.bed_level_order_num=000000000000000000000000000000";
            //开车时间
            strPostData += "&orderRequest.start_time=" + HttpUtility.UrlEncode(ti.Train_start_time);
            //到达时间
            strPostData += "&orderRequest.end_time=" + HttpUtility.UrlEncode(ti.Arrive_time);
            //出发站名
            strPostData += "&orderRequest.from_station_name=" + HttpUtility.UrlEncode(ti.From_station_name);
            //到达站名
            strPostData += "&orderRequest.to_station_name=" + HttpUtility.UrlEncode(ti.To_station_name);
            //不知道
            strPostData += "&orderRequest.cancel_flag=1";
            strPostData += "&orderRequest.id_mode=Y";
            strPostData += "&" + strOrderRandControl;

            //订票信息
            //席别，成人票，姓名，二代身份证，证件号码，手机，保存到常用联系人
            //席别：9、商务座；M、一等座；O、二等座；1、硬座；2、软座；3、硬卧；4、软卧；6、高级软卧
            for (int j = 0; j < dgvInfo.Rows.Count - 1; j++)
            {
                DataGridViewRow dgvr = dgvInfo.Rows[j];
                for (int k = 0; k < dgvInfo.Columns.Count; k++)
                {
                    //null什么的最烦了
                    if (dgvr.Cells[k].Value == null) dgvr.Cells[k].Value = "";
                }

                //删除空白行
                if (dgvr.Cells[0].Value.ToString() == "" &&
                    dgvr.Cells[1].Value.ToString() == "" &&
                    dgvr.Cells[2].Value.ToString() == "")
                {
                    dgvInfo.Rows.Remove(dgvr);
                    continue;
                }
                //strPostData += "&passengerTickets=" + HttpUtility.UrlEncode(dSeatType[cbSeatType.SelectedItem.ToString()] + ",0,1," + dgvr.Cells[0].Value.ToString() + ",1," + dgvr.Cells[1].Value.ToString() + "," + dgvr.Cells[2].Value.ToString() + ",Y");
                strPostData += "&passengerTickets=" + HttpUtility.UrlEncode(lbSeatType.SelectedValue.ToString() + ",0," + dgvr.Cells["dgvcTicketType"].Value.ToString() + "," + dgvr.Cells["dgvCName"].Value.ToString() + "," + dgvr.Cells["dgvcIDType"].Value.ToString() + "," + dgvr.Cells["dgvcID"].Value.ToString() + "," + dgvr.Cells["dgvcMobile"].Value.ToString() + ",N");
                //strPostData
            }

            //验证码
            strPostData += "&randCode=" + txtOrderPassCode.Text;
            //支付方式（就设A，不用管）
            strPostData += "&orderRequest.reserve_flag=A";

            return strPostData;
        }

        /// <summary>
        /// 处理订票状态
        /// </summary>
        /// <returns>1:订票成功;-10:订单状态确认倒计数，刷新自己;-20:未知错误，刷新订票页面</returns>
        private int handleOrderStatus()
        {
            //订单状态链接
            //其中tourFlag=dc表示单程
            Uri uriOrderAction = new Uri(wbLink.uriBase + "otsweb/order/myOrderAction.do?method=queryOrderWaitTime&tourFlag=dc");

            //返回数据的流
            HttpWebResponse respRtn;

            //返回的字符串
            String strOrderStatus;

            //订票成功会有订单号
            Regex rgOrderSuccess = new Regex("\"waitTime\":(-?\\d+?),\"waitCount\":(-?\\d+?),(?=\"orderId\":\"(\\w+?)\")?");
            //订票失败会有错误信息
            Regex rgOrderErr = new Regex("\"msg\":\"(.*?)\"");

            //不断循环直到订票成功或者失败
            try
            {
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uriOrderAction);
                request.Headers["x-requested-with"] = "XMLHttpRequest";
                request.Referer = wbLink.uriBase + "otsweb/order/confirmPassengerAction.do?method=init";
                request.Accept = "application/json, text/javascript, */*";
                request.ContentType = "application/x-www-form-urlencoded";

                respRtn = wbLink.SendData(request, ref cookconReq);

                strOrderStatus = wbLink.ReadStream(respRtn);
                txtLog.AppendText("♢问问服务器有没有订票成功。\r\n");
                //订票成功
                if (rgOrderSuccess.Match(strOrderStatus).Success)
                {
                    if (rgOrderSuccess.Match(strOrderStatus).Groups[2].Value.Trim() != "0")
                    {
                        txtLog.AppendText("♢服务器说，你前面还有" + rgOrderSuccess.Match(strOrderStatus).Groups[2].Value + "人。我也不知道它说得是否靠谱。\r\n");
                        //订单状态确认倒计数，刷新自己
                        return -10;
                    }
                    if (rgOrderSuccess.Match(strOrderStatus).Groups[3].Value != "")
                    {
                        txtLog.AppendText("♢订单号：" + rgOrderSuccess.Match(strOrderStatus).Groups[3].Value + "\r\n");
                        //成功
                        return 1;
                    }
                }

                //订票失败
                if (rgOrderErr.Match(strOrderStatus).Success)
                {
                    txtLog.AppendText("【服务器返回消息】" + rgOrderErr.Match(strOrderStatus).Groups[1].Value + "\r\n");
                    return -20;
                }
                //什么都没取到，刷新自己
                txtLog.AppendText("【未知错误】程序默认重新订票。请将下面的日志信息复制给程序作者，谢谢。\r\n");
                txtLog.AppendText(strOrderStatus + "\r\n");
                return -20;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 重设界面
        /// </summary>
        /// <param name="PgmAccess">1500：特别状态，订票超过数量，封死界面</param>
        private void resetForm(int PgmAccess)
        {
            //对界面进行重新设置
            if (PgmAccess == 0)
            {
                btnReLoginAndSearch.Text = "开始(&B)";
                btnReLoginAndSearch.Visible = true;
                btnPause.Visible = false;
            }

            if (PgmAccess < 30)
            {
                gbLogin.Enabled = true;
                gbSearch.Enabled = true;
                gbOrder.Enabled = true;
            }
            else if (PgmAccess < 60)
            {
                gbLogin.Enabled = false;
                gbSearch.Enabled = true;
                gbOrder.Enabled = true;
            }
            else if (PgmAccess < 900)
            {
                gbLogin.Enabled = false;
                gbSearch.Enabled = false;
                gbOrder.Enabled = true;
            }

            //特别状态，订票超过数量，封死界面
            if (PgmAccess == 1500)
            {
                gbLogin.Enabled = false;
                gbSearch.Enabled = false;
                gbOrder.Enabled = false;
                gbButton.Enabled = false;
            }

            PgmAccessBackup = 0;
        }

        /// <summary>
        /// 重新获取验证码
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void pbLoginPassCode_Click(object sender, EventArgs e)
        {
            try
            {
                getPassCode((new Random(DateTime.Now.Millisecond).NextDouble()).ToString(), 'L');
                identifyAuthCode('L');
            }
            catch (Exception ex)
            {
                MessageBox.Show(wbLink.strProcessError(ex), "出错了，请重试", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        /// <summary>
        /// 识别验证码并显示到文本框
        /// </summary>
        /// <param name="LoginOrBook">判断是登陆还是预定</param>
        /// <returns>是否识别成功，手动识别一概认为识别成功</returns>
        private Boolean identifyAuthCode(Char LoginOrBook)
        {
            String strAuthCode;
            
            if (cbAuthManual.Checked)
            {
                //手动识别验证码
                FrmOrderPassCode fopc = new FrmOrderPassCode(this, LoginOrBook);
                fopc.ShowDialog();
                //手动识别一概认为识别成功
                return true;
            }
            else
            {
                //自动识别验证码
                if (LoginOrBook == 'L')
                {
                    strAuthCode = GetAuthCode.get(new Bitmap(pbLoginPassCode.Image));
                    txtLoginPassCode.Text = strAuthCode;
                }
                else
                {
                    strAuthCode = GetAuthCode.get(new Bitmap(pbOrderPassCode.Image));
                    txtOrderPassCode.Text = strAuthCode;
                }
                if (strAuthCode.Length == 4)
                {
                    txtLog.AppendText("♢验证码为：" + strAuthCode + "\r\n");
                    return true;
                }
                else
                {
                    txtLog.AppendText("♢验证码识别失败。\r\n");
                    return false;
                }
            }
        }

        /// <summary>
        /// 获取验证码
        /// </summary>
        /// <param name="strRandom">随机值</param>
        /// <param name="LoginOrBook">判断是登陆还是预定</param>
        /// <returns>0:失败;1:成功</returns>
        public int getPassCode(String strRandom, Char LoginOrBook)
        {
            try
            {
                //返回数据的流
                HttpWebResponse respRtn;
                String strUrl;
                //登陆
                if (LoginOrBook == 'L')
                {
                    strUrl = "otsweb/passCodeNewAction.do?module=login&rand=sjrand";
                }
                //预定
                else
                {
                    strUrl = "otsweb/passCodeNewAction.do?module=passenger&rand=randp";
                }
                if (strRandom != "")
                {
                    strUrl += "&" + strRandom;
                }
                //获取验证码
                Uri uriPassCode = new Uri(wbLink.uriBase, strUrl);
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uriPassCode);
                request.Accept = "image/png, image/svg+xml, image/*;q=0.8, */*;q=0.5";
                if (LoginOrBook == 'L')
                {
                    request.Referer = wbLink.uriBase + "otsweb/loginAction.do?method=init";
                }
                else
                {
                    request.Referer = wbLink.uriBase + "otsweb/order/confirmPassengerAction.do?method=init";
                }


                respRtn = wbLink.SendData(request, ref cookconReq);

                //获取验证码，并显示
                if (LoginOrBook == 'L')
                {
                    pbLoginPassCode.Image = new Bitmap(respRtn.GetResponseStream());
                    //pbLoginPassCode.Image.Save("untitled.png");
                }
                else
                {
                    pbOrderPassCode.Image = new Bitmap(respRtn.GetResponseStream());
                }
                return 1;
            }
            catch (Exception ex)
            {
                txtLog.AppendText(ex.Message + "\r\n");
                return 0;
            }
        }

        /// <summary>
        /// 播放音乐
        /// </summary>
        private void playBeep()
        {
            //音乐也可以手动点击停止
            while (!bgdWorkerReLoginAndSearch.CancellationPending)
            {
                System.Media.SystemSounds.Beep.Play();
                Thread.Sleep(1000);
            }
        }

        /// <summary>
        /// 判断是否被踢了
        /// </summary>
        private bool IsLogOut(String strPage)
        {
            //不含isLogin，则应该是那些json的页面，暂时认为登陆状态为true
            //当然，如果显示系统维护中，则还是认为没有登录
            if (!strPage.Contains("isLogin") && !strPage.Contains("系统维护中"))
            {
                return true;
            }
            Regex rgIsLogin = new Regex("var\\s+isLogin\\s*?=\\s*?(true|false)");
            if (rgIsLogin.Match(strPage).Success)
            {
                if (rgIsLogin.Match(strPage).Groups[1].Value == "true")
                {
                    //登录成功，就是说没有被踢
                    return false;
                }
            }
            return true;
        }

        //弹出新窗口
        private void PopIE()
        {
            String strUrl = wbLink.uriBase + "otsweb/";
            List<Cookie> lstCookies = GetAllCookies(cookconReq);
            foreach (Cookie c in lstCookies)
            {
                String strcv;
                if (c.Name == "JSESSIONID")
                {
                    strcv = c.Value + ";Path=/otsweb;expires=Sun,22-Feb-2099 00:00:00 GMT";
                }
                else
                {
                    strcv = c.Value + ";path=/;expires=Sun,22-Feb-2099 00:00:00 GMT";
                }
                //wbMain.Document.Cookie = c.Name + "=" + strcv;
                InternetSetCookie(strUrl, c.Name, strcv);
            }
            System.Diagnostics.Process.Start("IEXPLORE.EXE", strUrl);
        }


        //从CookieContainer获得值
        public static List<Cookie> GetAllCookies(CookieContainer cc)
        {
            List<Cookie> lstCookies = new List<Cookie>();

            Hashtable table = (Hashtable)cc.GetType().InvokeMember("m_domainTable",
                System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.GetField |
                System.Reflection.BindingFlags.Instance, null, cc, new object[] { });

            foreach (object pathList in table.Values)
            {
                SortedList lstCookieCol = (SortedList)pathList.GetType().InvokeMember("m_list",
                    System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.GetField
                    | System.Reflection.BindingFlags.Instance, null, pathList, new object[] { });
                foreach (CookieCollection colCookies in lstCookieCol.Values)
                    foreach (Cookie c in colCookies) lstCookies.Add(c);
            }
            return lstCookies;
        }

        private void btnStopSearch_Click(object sender, EventArgs e)
        {
            //完全停止
            PgmAccessBackup = -1;
            bgdWorkerReLoginAndSearch.CancelAsync();
            txtLog.AppendText("♢准备停止，队列中最后一步的操作必须全部执行完毕方能停止。\r\n");
        }

        private void FrmMain_Load(object sender, EventArgs e)
        {
            //规避错误：从不是创建控件“”的线程访问它
            Control.CheckForIllegalCrossThreadCalls = false;

            //初始化窗体上的定值
            #region 初始值设置
            //席别：9、商务座；M、一等座；O、二等座；1、硬座；3、硬卧；4、软卧；6、高级软卧
            lbSeatType.DataSource = Configuration.getSeatTypeDataTable();
            lbSeatType.DisplayMember = "SeatName";
            lbSeatType.ValueMember = "SeatID";

            //票种：1、成人票；2、儿童票；3、学生票；4、残军票
            dgvcTicketType.DataSource = Configuration.getTicketTypeDataTable();
            dgvcTicketType.DisplayMember = "TicketName";
            dgvcTicketType.ValueMember = "TicketID";

            //证件：1、二代身份证；2、一代身份证；C、港澳通行证；G、台湾通行证；B、护照
            dgvcIDType.DataSource = Configuration.getIDType();
            dgvcIDType.DisplayMember = "TypeName";
            dgvcIDType.ValueMember = "TypeID";

            //日期
            dtpGoDate.Value = DateTime.Now.AddDays(19);
            #endregion

            #region 控件设置
            ToolTip tt = new ToolTip();
            tt.InitialDelay = 500;
            tt.ReshowDelay = 500;
            tt.SetToolTip(this, "“怎么回来的啊？”“我抢了别人的票，这才回来了。”");
            //tt.SetToolTip(pbLoginPassCode, "点击后刷新验证码");
            //tt.SetToolTip(pbOrderPassCode, "点击后刷新验证码");

            cbGoTime.SelectedIndex = 0;

            lblInfo.Text = "未通读压缩包内文档者，禁止提问；\r\n";
            lblInfo.Text += "感谢某神秘大侠提供验证码识别模块，该模块他仅花了几个小时就搞定了；\r\n";
            lblInfo.Text += "我在此为其图像识别业务做个推广，有业务需求的请到Dll里去找联系方式；\r\n";
            lblInfo.Text += "代人订票，加价超过五元者，属倒卖车票罪，最高可以判三年；\r\n";
            lblInfo.Text += "本软件完全免费。禁止任何人以任何方式通过本软件牟利。如果你是从淘宝买到的本软件，那请以本条款为依据申请退款或直接给差评，并给与投诉。";

            //初始化微博秀页面
            strWeiBoUrl = "http://widget.weibo.com/weiboshow/index.php?language=&width=0&height=" + wbAdv.Height + "&fansRow=1&ptype=1&speed=0&skin=8&isTitle=0&noborder=0&isWeibo=1&isFans=1&uid=2520398727&verifier=6c8e236a&colors=d6f3f7,464646,e0e0e0,b4b4b4,353535&dpc=1";
            wbAdv.Navigate(strWeiBoUrl + "&" + DateTime.Now.Ticks.ToString());
            //将webbrowser的弹出窗口事件捕获
            ((SHDocVw.DWebBrowserEvents_Event)wbAdv.ActiveXInstance).NewWindow += BrowserNewWindow;

            //初始化计数器
            wbStats.DocumentText = "<a href='#'><img src='http://gostats.cn/bin/count/a_749003/t_5/i_1/counter.png' style='border-width:0' /></a>";
            #endregion

            //设置连接信息
            setWebBot();

            #region 读取配置文件
            try
            {
                //初始化界面
                txtUserName.Text = System.Configuration.ConfigurationManager.AppSettings["UserName"];
                txtPassword.Text = System.Configuration.ConfigurationManager.AppSettings["PassWord"];
                txtFromStation.Text = System.Configuration.ConfigurationManager.AppSettings["FromStation"];
                txtToStation.Text = System.Configuration.ConfigurationManager.AppSettings["ToStation"];
                txtTrainCode.Text = System.Configuration.ConfigurationManager.AppSettings["TrainCode"];
                dtpStartTime.Value = new DateTime(Convert.ToInt64(System.Configuration.ConfigurationManager.AppSettings["StartTime"]));
                lbSeatType.SelectedIndex = Convert.ToInt16(System.Configuration.ConfigurationManager.AppSettings["SeatType"]);
                if (!String.IsNullOrEmpty(System.Configuration.ConfigurationManager.AppSettings["TicketInfo"]))
                {
                    String[] strDgvRow = System.Configuration.ConfigurationManager.AppSettings["TicketInfo"].Split('#');
                    for (int i = 0; i < strDgvRow.Length; i++)
                    {
                        dgvInfo.Rows.Add(strDgvRow[i].Split('|'));
                    }
                }
            }
            catch
            {
                MessageBox.Show("配置文件损坏，请重新下载程序！", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                Application.Exit();
            }
            #endregion

            #region 初始化时的多线程操作

            initLogin();

            #endregion
        }

        /// <summary>
        /// 设置连接信息
        /// </summary>
        public void setWebBot()
        {
            System.Configuration.Configuration cfg = System.Configuration.ConfigurationManager.OpenExeConfiguration(System.Configuration.ConfigurationUserLevel.None);
            String[] strArrProxyPara = DES.DecryptDES(cfg.AppSettings.Settings["Proxy"].Value, DES.strDESKey).Split('|');
            //是否使用默认代理
            Boolean IsUseDefaultProxy = false;
            if (cfg.AppSettings.Settings["UseDefaultProxy"].Value == "Y")
            {
                IsUseDefaultProxy = true;
            }
            wbLink = new WebBot(strArrProxyPara[0], strArrProxyPara[1], strArrProxyPara[2], strArrProxyPara[3], IsUseDefaultProxy);
        }

        public void initLogin()
        {
            try
            {
                //初始化登录
                Thread td = new Thread(checkTicketCount);
                td.Start();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + "\r\n请重新运行程序。", "出错了，请重新运行程序", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        /// <summary>
        /// 初始化时的多线程操作
        /// </summary>
        private void checkTicketCount()
        {
            //设置线程为后台线程，以便在主线程退出时退出
            Thread.CurrentThread.IsBackground = true;

            //将设置按钮设为不可用
            btnSetup.Enabled = false;

            try
            {
                //读注册表以获取订票限制
                String strFirstOrderDateTime;
                txtLog.AppendText("♢正在进行初始化。\r\n");
                OrderLimit.wbOrderLimitLink = wbLink;
                int iOrderLimitCheck = OrderLimit.LimitCheck(out strFirstOrderDateTime);
                switch (iOrderLimitCheck)
                {
                    case -1:
                        MessageBox.Show("半桶水！改注册表改坏了吧。", "活该", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        txtLog.AppendText("♢您将不得再用此软件。\r\n");
                        break;
                    case 0:
                        txtLog.AppendText("♢已订票数量超过限制。\r\n");
                        txtLog.AppendText("♢每" + OrderLimit.lOrderCheckPeriod / (60 * 60 * 10000000L) + "小时只能订" + OrderLimit.iMaxOrderCount + "张票。\r\n");
                        txtLog.AppendText("♢系统记录，你最早一次订票时间是：" + strFirstOrderDateTime + "\r\n");
                        resetForm(1500);
                        txtLog.AppendText("♢程序已中止，如有需要请重新点击开始！\r\n");
                        break;
                    default:
                        txtLog.AppendText("♢你还可以订" + iOrderLimitCheck + "张票。\r\n");
                        iOrderLimit = iOrderLimitCheck;
                        break;
                }
                txtLog.AppendText("♢初始化完成。\r\n");
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "初始化失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
                iOrderLimit = -1;
                txtLog.AppendText("♢初始化失败。\r\n");
                //Application.Exit();
            }
            finally
            {
                //将设置按钮恢复
                btnSetup.Enabled = true;
            }
        }

        /// <summary>
        /// 捕获弹出新窗口事件
        /// </summary>
        /// <param name="url">新窗口的地址</param>
        /// <param name="flag"></param>
        /// <param name="target">目标</param>
        /// <param name="data">Post数据</param>
        /// <param name="header">request头</param>
        /// <param name="processed"></param>
        private void BrowserNewWindow(string url, int flag, string target, ref object data, string header, ref bool processed)
        {
            //如果弹出的是微博登录窗口，就拦截这个窗口，并在webbrowser里打开
            //这么做的原因是，有时候webbrowser的cookie和IE的cookie不共享，而弹出的窗口都是用IE的cookie
            //这样的话，微博秀就始终无法添加关注。
            //这么做的另外一个原因是，弹出窗口关闭的事件无法捕获
            if (url.Contains("http://service.weibo.com/reg/loginindex.php"))
            {
                processed = true;
                wbAdv.Navigate(url);
            }
        }
        /// <summary>
        /// 微博秀登录结束页面
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void wbAdv_Navigating(object sender, WebBrowserNavigatingEventArgs e)
        {
            //微博登录结束后，迁移回微博秀页面，为了让后续模拟Click事件的程序能识别，特意在链接中加了本程序的身份标识
            if (e.Url.AbsoluteUri == "http://widget.weibo.com/staticjs/loginProxy.html")
            {
                e.Cancel = true;

                wbAdv.Navigate(strWeiBoUrl + "&" + strIdentify + "&" + DateTime.Now.Ticks.ToString());
            }

        }
        /// <summary>
        /// 模拟Click事件，只能放在这里，放在别处无效
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void wbAdv_ProgressChanged(object sender, WebBrowserProgressChangedEventArgs e)
        {
            //根据程序身份标识来断定，当前的页面是微博登录结束后的页面
            if (((WebBrowser)sender).Url != null && ((WebBrowser)sender).Url.AbsoluteUri.Contains(strIdentify))
            {
                wbAdv.Document.GetElementById("followBtn").InvokeMember("Click");
            }
        }

        private void TmrAdv_Tick(object sender, EventArgs e)
        {
            //刷新浏览器
            wbAdv.Refresh();
        }

        //Ctrl+A全选
        private void txtLog_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.Modifiers == Keys.Control && e.KeyCode == Keys.A)
            {
                ((TextBox)sender).SelectAll();
            } 
        }

        private void txtLog_TextChanged(object sender, EventArgs e)
        {
            txtLog.ScrollToCaret();
        }

        private void btnManaul_Click(object sender, EventArgs e)
        {
            PopIE();
        }

        private void btnPause_Click(object sender, EventArgs e)
        {
            btnPause.Visible = false;
            btnReLoginAndSearch.Visible = true;
            btnReLoginAndSearch.Text = "恢复(&R)";
            bgdWorkerReLoginAndSearch.CancelAsync();
            txtLog.AppendText("♢即将暂停，队列中最后一步的操作必须全部执行完毕方能暂停。\r\n");
        }

        //关闭前保存
        private void FrmMain_FormClosing(object sender, FormClosingEventArgs e)
        {
            System.Configuration.Configuration cfg = System.Configuration.ConfigurationManager.OpenExeConfiguration(System.Configuration.ConfigurationUserLevel.None);
            cfg.AppSettings.Settings["UserName"].Value = txtUserName.Text;
            cfg.AppSettings.Settings["PassWord"].Value = txtPassword.Text;
            cfg.AppSettings.Settings["FromStation"].Value = txtFromStation.Text;
            cfg.AppSettings.Settings["ToStation"].Value = txtToStation.Text;
            cfg.AppSettings.Settings["TrainCode"].Value = txtTrainCode.Text;
            cfg.AppSettings.Settings["StartTime"].Value = dtpStartTime.Value.Ticks.ToString();
            cfg.AppSettings.Settings["SeatType"].Value = lbSeatType.SelectedIndex.ToString();

            StringBuilder strTicketInfo = new StringBuilder();
            for (int i = 0; i < dgvInfo.Rows.Count - 1; i++)
            {
                if (i != 0)
                {
                    strTicketInfo.Append("#");
                }
                for (int j = 0; j < dgvInfo.Columns.Count; j++)
                {
                    if (j != 0)
                    {
                        strTicketInfo.Append("|");
                    }
                    if (dgvInfo.Rows[i].Cells[j].Value != null)
                    {
                        strTicketInfo.Append(dgvInfo.Rows[i].Cells[j].Value);
                    }
                }
            }
            cfg.AppSettings.Settings["TicketInfo"].Value = strTicketInfo.ToString();
            cfg.Save();
        }

        private void cbNoStand_CheckedChanged(object sender, EventArgs e)
        {
            if (cbNoStand.Checked)
            {
                txtLog.AppendText("■本功能并不靠谱，会大幅度降低刷票效率，且依然有可能订到站票。除非你没座就不回家了，否则不建议勾选此项。\r\n");
            }
        }

        private void cbCircle_CheckedChanged(object sender, EventArgs e)
        {
            if (cbCircle.Checked)
            {
                txtLog.AppendText("■本模式会忽略很多错误，不间断地进行循环，因此请务必确认你输入的信息是正确的。\r\n");
            }
        }

        private void txtMinIntev_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar != 8 && !Char.IsDigit(e.KeyChar))
            {
                e.Handled = true;
            }
        }

        private void txtMaxIntev_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar != 8 && !Char.IsDigit(e.KeyChar))
            {
                e.Handled = true;
            }
        }

        private void btnSetup_Click(object sender, EventArgs e)
        {
            //手动识别验证码
            FrmSetup fs = new FrmSetup(this);
            fs.ShowDialog();
        }

        //保存验证码的标示
        private Boolean saveAuthCode = false;
        //手动识别验证码的话保存
        private void SaveAuthCode(Char LoginOrOrder)
        {
            if (cbAuthManual.Checked)
            {
                System.IO.DirectoryInfo fdir = new System.IO.DirectoryInfo("请将我发送给作者，邮件地址见文档\\");
                if (!fdir.Exists)
                {
                    fdir.Create();
                }
                if (LoginOrOrder == 'L')
                {
                    pbLoginPassCode.Image.Save(fdir.FullName + @"\" + txtLoginPassCode.Text.ToUpper() + "_212_" + DateTime.Now.Ticks.ToString() + ".png");
                }
                else
                {
                    pbOrderPassCode.Image.Save(fdir.FullName + @"\" + txtOrderPassCode.Text.ToUpper() + "_212_" + DateTime.Now.Ticks.ToString() + ".png");
                }
            }
        }

        private void TmrCDN_Tick(object sender, EventArgs e)
        {
            c.Ping();
            c.AddIPIndex();
        }

        private void cbAuthManual_CheckedChanged(object sender, EventArgs e)
        {
            if (cbAuthManual.Checked)
            {
                cbLessTicket.Enabled = true;
            }
            else
            {
                cbLessTicket.Enabled = false;
                cbLessTicket.Checked = false;
            }
        }

        private void cbLessTicket_CheckedChanged(object sender, EventArgs e)
        {
            if (cbLessTicket.Checked)
            {
                txtLog.AppendText("■本模式以查询到的余票为准，但是这个余票信息不一定靠谱。所以请谨慎勾选。\r\n");
            }
        }
    }
}
